#include "wifi.h"  // 引入自定义的 WiFi 模块驱动头文件

#define WIFI_SSID ""  // WiFi 名称，需替换为实际 SSID
#define WIFI_PASSWORD ""  // WiFi 密码，需替换为实际密码
#define SERVER_IP ""    // 服务器IP，现场修改
#define SERVER_PORT 5000            // 服务器端口
#define DATA_COUNT 10               // 缓存重力加速度的次数（10次求平均）

Wifi wifi;  // 创建 WiFi 类实例

// 光电门引脚定义
#define PHOTO_GATE1 A0
#define PHOTO_GATE2 A1

// 光电门状态与时间变量
unsigned long gate1Time = 0;               // 光电门1当前触发时间(微秒)
unsigned long gate2Time = 0;               // 光电门2当前触发时间(微秒)
bool gate1State = LOW;                     // 光电门1当前状态
bool gate2State = LOW;                     // 光电门2当前状态
bool gate1LastState = LOW;                 // 光电门1上一状态
bool gate2LastState = LOW;                 // 光电门2上一状态
const unsigned long debounceTime = 50000;  // 防抖时间（50ms）
bool gate1Triggered = false;               // 光电门1是否完成一次有效触发
bool gate2Triggered = false;               // 光电门2是否完成一次有效触发

// 单摆周期计算变量（3次触发求完整周期，基于光电门1）
unsigned long gate1TriggerTimes[3] = { 0, 0, 0 };
int triggerCount = 0;               // 光电门1触发次数计数器（0-2循环）
const float pendulumLength = 0.31;  // 摆长（米，按实际修改）
const float pi = 3.1415926;         // π值

// 重力加速度缓存与计数（10次求平均）
float gravityBuffer[DATA_COUNT] = { 0 };  // 缓存10次重力加速度
int gravityCount = 0;                     // 已缓存的次数
float avgGravity = 0;                     // 重力加速度平均值

// float转char数组函数（原功能保留）
void floatToChar(float value, char *result, int bufferSize, int decimalPlaces = 4) {
  long multiplier = 1;
  for (int i = 0; i < decimalPlaces; i++) {
    multiplier *= 10;
  }

  long scaled = (long)(value * multiplier + (value >= 0 ? 0.5 : -0.5));
  int integerPart = scaled / multiplier;
  int fractionalPart = scaled % multiplier;
  int absFraction = abs(fractionalPart);

  char format[10];
  sprintf(format, "%%d.%%0%dd", decimalPlaces);
  snprintf(result, bufferSize, format, integerPart, absFraction);
}

// WiFi上传平均重力加速度函数（封装上传逻辑）
void uploadAvgGravity(float avgG) {

  // 先构造json数据
  char str1[15];
  floatToChar(avgG, str1, sizeof(str1), 4);  //avgGravity就是传感器的数据 该函数将浮点数转换为字符串（WCH库没有开浮点数打印）
  char jsonData[128];
  sprintf(jsonData, "{\"id\": 2, \"username\": \"alice\", \"value\": %s}", str1);  //注意id要改成自己的id，username要改成自己的用户名
  // 计算json数据的实际长度 用于发送json数据给服务器
  int jsonLen = strlen(jsonData);
  // 动态构造AT命令
  char httpCmd[256];
  sprintf((char *)httpCmd, "AT+HTTPRAW=1,3,\"application/json\",192.168.2.15,5000,\"/api/data\",%d", jsonLen);  //192.168.2.15是服务器的IP地址，现场修改
                                                                                                                 // 发送AT命令
  wifi.sendATCmd((u8 *)httpCmd, (u8 *)">", 4000);
  // 发送json数据
  wifi.sendATCmd((u8 *)jsonData, (u8 *)"OK", 10000);
}

// 双门均触发后，处理数据（打印时间+计算重力）
void processDualGateData() {
  // 1. 按格式打印双门触发时间
  Serial.print("get1:");
  Serial.print(gate1Time);
  Serial.print(",get2:");
  Serial.println(gate2Time);

  // 2. 基于光电门1的3次触发计算重力加速度
  if (gate1TriggerTimes[0] != 0 && gate1TriggerTimes[2] != 0) {
    unsigned long fullPeriodMicros = gate1TriggerTimes[2] - gate1TriggerTimes[0];
    float fullPeriodSec = fullPeriodMicros / 1000000.0;

    // 过滤异常周期（适配0.31m摆长）
    if (fullPeriodSec > 0.8 && fullPeriodSec < 1.5) {
      float gravity = (4 * pi * pi * pendulumLength) / (fullPeriodSec * fullPeriodSec);
      Serial.print("Single Gravity: ");
      Serial.print(gravity, 4);
      Serial.println(" m/s²");

      // 缓存重力加速度
      gravityBuffer[gravityCount] = gravity;
      gravityCount++;
      Serial.print("Cached Count: ");
      Serial.println(gravityCount);

      // 满10次数据，计算平均值并上传
      if (gravityCount >= DATA_COUNT) {
        avgGravity = 0;
        for (int i = 0; i < DATA_COUNT; i++) {
          avgGravity += gravityBuffer[i];
        }
        avgGravity /= DATA_COUNT;

        uploadAvgGravity(avgGravity);

        // 重置缓存
        gravityCount = 0;
        memset(gravityBuffer, 0, sizeof(gravityBuffer));
        Serial.println("Buffer Reset, Waiting for Next Dual-Gate Triggers...\n");
      }

      // 重置光电门1的3次触发数组
      memset(gate1TriggerTimes, 0, sizeof(gate1TriggerTimes));
    }
  }

  // 3. 重置双门触发标记，等待下一次双门触发
  gate1Triggered = false;
  gate2Triggered = false;
}

void setup() {
  pinMode(PHOTO_GATE1, INPUT);
  pinMode(PHOTO_GATE2, INPUT);

  Serial.begin(115200);
  while (!Serial)
    ;
  Serial.println("=== Pendulum System Ready ===");
  Serial.print("Set Pendulum Length: ");
  Serial.print(pendulumLength);
  Serial.println("m");
  Serial.println("Waiting for Both Photo Gates Trigger...\n");

  // 初始化WiFi模块
  wifi.init(115200);
  delay(1000);
  // 发送 AT 指令，等待返回 "OK"，超时时间 2000ms，用来检测模块是否正常工作
  wifi.sendATCmd((u8 *)"AT", (u8 *)"OK", 2000);

  // 查询当前 WiFi 模式，期望返回 "+WMODE:1"（Station 模式），超时 2000ms
  wifi.sendATCmd((u8 *)"AT+WMODE?", (u8 *)"+WMODE:1", 2000);

  u8 connectCmd[128];  // 定义一个 128 字节的数组，用于存放连接 WiFi 的 AT 指令
  // 格式化生成连接 WiFi 的 AT 命令，例如：AT+WJAP=SSID,PASSWORD
  sprintf((char *)connectCmd, "AT+WJAP=%s,%s", WIFI_SSID, WIFI_PASSWORD);
  // 发送连接 WiFi 的 AT 指令，等待获取 IP 地址事件 "+EVENT:WIFI_GOT_IP"，超时 10000ms
  wifi.sendATCmd(connectCmd, (u8 *)"+EVENT:WIFI_GOT_IP", 10000);
}

void loop() {
  unsigned long currentTime = micros();
  gate1State = digitalRead(PHOTO_GATE1);
  gate2State = digitalRead(PHOTO_GATE2);

  // -------------------------- 1. 光电门1触发处理 --------------------------
  if (gate1State == HIGH && gate1LastState == LOW && (currentTime - gate1Time) > debounceTime) {
    gate1Time = currentTime;
    gate1Triggered = true;  // 标记光电门1已触发

    // 存储光电门1的触发时间（用于计算周期）
    gate1TriggerTimes[triggerCount] = gate1Time;
    triggerCount = (triggerCount + 1) % 3;
  }

  // -------------------------- 2. 光电门2触发处理 --------------------------
  if (gate2State == HIGH && gate2LastState == LOW && (currentTime - gate2Time) > debounceTime) {
    gate2Time = currentTime;
    gate2Triggered = true;  // 标记光电门2已触发
  }

  // -------------------------- 3. 双门均触发后，处理数据 --------------------------
  if (gate1Triggered && gate2Triggered) {
    processDualGateData();
  }

  // 更新上一状态
  gate1LastState = gate1State;
  gate2LastState = gate2State;
}